import time
from tkinter import NORMAL, DISABLED
from selenium.common.exceptions import TimeoutException, WebDriverException
from taobao_check.tools import get_browser, run_async, BaseSelenium, get_logger, PATH
from taobao_check.check import UserCheck


class BaseBrush(BaseSelenium):
    refresh_time = 20
    memory_limit = 500
    end = False
    check = None
    env_ok = False
    login_url = ""
    index_url = ""
    check_url = ""

    def __init__(self, name, key, config, tab):
        super().__init__()
        self.key = key
        self.name = name
        self.config = config
        self.tab = tab
        self.print_log = tab.print_log
        self.logger = get_logger(PATH.error_log, f"{key}_error.txt")
        self.init_config()
        self.no_log = False
        self.tab.user_label.config(text=f"【{config.account.username}】")
        self.tab.start_btn.config(command=self.start_running)
        self.tab.stop_btn.config(command=self.stop_running)
        self.actions = {"START": self.do_nothing,
                        "LOGIN": self.do_login,
                        "CHECK": self.do_check,
                        "MEMORY": self.do_check_memory,
                        "STOP": self.do_stop,
                        "ERROR": self.do_error}
        self.state = "START"

    def init_config(self):
        self.username, self.password = self.config.account[self.key]
        self.debug = self.config.debug[self.key]

    def check_permission(self):
        self.init_config()
        if self.username == "18xxxxxxxxx":
            self.print_log("请先配置账号信息再使用.\n")
            return False
        if self.username not in self.config.user.phone:
            self.print_log(f"手机号【{self.username}】没有使用此软件的权限。")
            self.print_log(f"请修改账号信息或者联系管理员添加。\n")
            return False

        return True

    @run_async
    def start(self):
        self.print_log(f"{self.name}登录地址: {self.login_url}\n")
        self.print_log("点击【开始验号】开始.\n")
        self.tab.start_btn.config(state=NORMAL)
        while self.state != "QUIT":
            try:
                if self.state != "START":
                    self.print_log(self.state, debug=True)
                self.actions[self.state]()
            except Exception as e:
                self.logger.exception(e)
                self.do_error(e)

    def start_running(self):
        if not self.check_permission():
            return
        self.state = "LOGIN"
        self.tab.set_label("登录中", "green")
        self.tab.start_btn.config(state=DISABLED)

    def stop_running(self):
        self.state = "STOP"
        self.end = True
        self.print_log(f"正在停止{self.name}买号审核...")
        self.tab.set_label("停止中", "blue")
        self.tab.stop_btn.config(state=DISABLED)
        self.no_log = False

    def do_nothing(self):
        time.sleep(0.2)

    def do_login(self):
        self.quit()
        self.init_config()
        self.check = UserCheck(self.config, self.tab.print_log, self.no_log)
        if not self.check.env_ok:
            if self.no_log:
                self.set_state("LOGIN")
            else:
                self.set_state("START")
            self.tab.start_btn.config(state=NORMAL)
            return "START"

        self.do_login_brush()
        self.print_log(f"{self.name}买号审核启动成功.", debug=self.no_log)
        self.no_log = True
        self.set_state("CHECK")

    def do_login_brush(self):
        self.print_log(f"开始登录{self.name}...", debug=self.no_log)
        start = time.time()

        if self.debug:
            self.browser = get_browser(headless=False, load_image=True)
        else:
            self.browser = get_browser()
        self.login()
        self.print_log(f"{self.name}登录成功!用时{time.time()-start:.2f}", debug=self.no_log)

    def do_check(self):
        self.set_state("CHECK")
        self.tab.set_label("运行中", "green")
        self.tab.start_btn.config(state=DISABLED)
        self.tab.stop_btn.config(state=NORMAL)
        self.browser.get(self.check_url)
        if self.browser.current_url == self.login_url:
            self.set_state("LOGIN")
            return "LOGIN"

        buy = self.check_user()
        if not buy:
            self.set_state("MEMORY")

    def do_check_memory(self):
        memory = self.get_memory()
        if memory > self.memory_limit:
            self.print_log(f"{self.name}内存过载，即将重启...", debug=True)
            self.set_state("LOGIN")
        else:
            self.set_state("CHECK")

    def do_stop(self):
        self.tab.set_label("未开始", "red")
        self.quit()
        self.browser = None
        self.check = None
        self.tab.start_btn.config(state=NORMAL)
        self.tab.stop_btn.config(state=DISABLED)
        self.print_log(f"{self.name}买号审核停止成功.")
        self.state = "START"

    def do_error(self, e):
        if self.state == "LOGIN":
            self.print_log(f"登录出错，原因为: {e}", debug=True)
        elif self.state == "CHECK":
            self.print_log(f"验号出错，原因为: {e}", debug=True)
        else:
            self.print_log(f"运行出错，原因为: {e}", debug=True)
        self.print_log(f"即将重新登录...", debug=self.no_log)
        self.set_state("LOGIN")

    def sleep(self, seconds):
        start = time.time()
        while not self.end and (time.time() - start < seconds):
            time.sleep(0.2)

    def set_state(self, state):
        if self.state != "STOP":
            self.state = state

    def quit(self, state=False):
        if state:
            self.end = True
            self.state = "QUIT"
        try:
            self.browser.quit()
            self.check.quit()
        except:
            pass

    def get_total_memory(self):
        return self.get_memory() + self.check.get_memory()

    def wait_login(self, timeout=-1):
        if timeout < 0:
            timeout = self.timeout
        start = time.time()
        while self.browser.current_url != self.index_url:
            if time.time() - start > timeout:
                return False
            time.sleep(0.2)
        return True

    def login(self):
        """留给子类实现"""

    def check_user(self):
        """
        留给子类实现，每次调用都是一次查询是否有买号的过程，
        有买号则处理，最后结果返回True，如果没有卖号则返回False
        """
